package blackstar.performance.transform.instrutment;

import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import blackstar.performance.exception.PerformanceException;
import blackstar.performance.transform.matcher.PointCutMatcher;

/**
 * @author raywu (ayufox@gmail.com)
 * 
 */
public class PerformanceClassVisitor extends ClassAdapter implements Opcodes
{
	public final static int TYPE_PERFORMANCE = 1;
	public final static int TYPE_DETAIL_PERFORMANCE = 2;
	private PointCutMatcher methodMatcher;
	private String className;
	private boolean change = false;
	private int type = 0;

	public PerformanceClassVisitor(ClassVisitor classvisitor, String className)
	{
		this(classvisitor, null, TYPE_PERFORMANCE, className);
	}

	public PerformanceClassVisitor(ClassVisitor classvisitor, int type, String className)
	{
		this(classvisitor, null, type, className);
	}

	public PerformanceClassVisitor(ClassVisitor classvisitor,
			PointCutMatcher methodMatcher, int type, String className)
	{
		super(classvisitor);
		this.methodMatcher = methodMatcher;
		this.type = type;
		this.className = className;
	}

	public MethodVisitor visitMethod(int access, String name, String desc,
			String signature, String[] exceptions)
	{
		MethodVisitor visitor = super.visitMethod(access, name, desc,
				signature, exceptions);
		if ("<init>".equals(name))
		{
			return visitor;
		}

		if ("<clinit>".equals(name))
		{
			return visitor;
		}

		if ("main".equals(name))
		{
			return visitor;
		}

		if ((access & ACC_NATIVE) > 0 || (access & ACC_ABSTRACT) > 0
				|| (access & ACC_INTERFACE) > 0)
		{
			return visitor;
		}

		if (this.methodMatcher != null
				&& !this.methodMatcher.isMethodMatch(name + desc))
		{
			return visitor;
		}
		
		change = true;

		switch (this.type)
		{
		case TYPE_PERFORMANCE:
			return new InvokePerformanceMethodAdapter(className, name, access,
					desc, visitor);
		case TYPE_DETAIL_PERFORMANCE:
			return new InvokeDetailPerformanceMethodAdapter(className, name,
					access, desc, visitor);
		default:
			throw new PerformanceException("Error Performance Type["
					+ this.type + "]");
		}
	}

	public boolean isChange()
	{
		return change;
	}
}
